/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ytmc.downloader;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.tidy.Tidy;

/**
 *
 * @author K
 */
public class VideoDownloadLinkRetriver
{
    private final Object lock = new Object();

    private String videoDownloadURL;

    public String getVideoDownloadURL()
    {
        return videoDownloadURL;
    }

    public void setVideoDownloadURL(String videoDownloadURL)
    {
        synchronized (lock)
        {
            if(this.videoDownloadURL.equals(videoDownloadURL))
                return;

            String oldValue = this.videoDownloadURL;
            this.videoDownloadURL = videoDownloadURL;
            notifyPropertyChangeListeners(new PropertyChangeEvent(this, "videoDownloadURL", oldValue, videoDownloadURL));
        }
    }

    private String videoWatchURL;

    public String getVideoWatchURL()
    {
        return videoWatchURL;
    }

    private ArrayList<PropertyChangeListener> listeners;

    public void addPropertyChangeListener(PropertyChangeListener listener)
    {
        synchronized (lock)
        {
            if (!listeners.contains(listener))
            {
                listeners.add(listener);
            }
        }
    }

    public void removePropertyChangeListener(PropertyChangeListener listener)
    {
        synchronized (lock)
        {
            if (listeners.contains(listener))
            {
                listeners.remove(listener);
            }
        }
    }

    private void notifyPropertyChangeListeners(PropertyChangeEvent event)
    {
        for (PropertyChangeListener propertyChangeListener : listeners)
        {
            propertyChangeListener.propertyChange(event);
        }
    }

    public void retrieve()
    {
        try
        {
            Document content = makeContentTidy(retrieveContent());
            String url = retrieveDownloadURL(content);
            setVideoDownloadURL(url);
        }
        catch (MalformedURLException ex)
        {
            Logger.getLogger(VideoDownloadLinkRetriver.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (IOException ex)
        {
            Logger.getLogger(VideoDownloadLinkRetriver.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (XPathExpressionException ex)
        {
            Logger.getLogger(VideoDownloadLinkRetriver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void retrieveAsync()
    {
        Thread worker = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                retrieve();
            }
        });
        worker.start();
    }

    private String retrieveContent() throws MalformedURLException, IOException
    {
        String line;
        BufferedReader reader = null;
        StringBuilder result = new StringBuilder();

        try
        {
            URL u = new URL(videoWatchURL);
            reader = new BufferedReader(new InputStreamReader(u.openStream()));
            while ((line = reader.readLine()) != null)
            {
                result.append(line);
                result.append(System.getProperty("line.separator"));
            }
        }
        finally
        {
            if (reader != null)
                reader.close();
        }

        return result.toString();
    }

    private Document makeContentTidy(String content)
    {
        Tidy tidy = new Tidy();
        tidy.setQuiet(true);
        tidy.setShowWarnings(false);
        tidy.setShowErrors(0);

        return tidy.parseDOM(new StringReader(content.toString()), null);
    }

    private String retrieveDownloadURL(Document content) throws XPathExpressionException, UnsupportedEncodingException
    {
        XPath xPath = XPathFactory.newInstance().newXPath();

        String linkBlock = xPath.evaluate("//*[@id=\"movie_player\"]/@flashvars", content);
        String decodedLinkBlock = URLDecoder.decode(linkBlock, "UTF-8");
        int start = decodedLinkBlock.indexOf("http", decodedLinkBlock.indexOf("fmt_url_map"));
        int end = decodedLinkBlock.indexOf(",", start);

        return decodedLinkBlock.substring(start, end);
    }

    public VideoDownloadLinkRetriver(String videoWatchURL)
    {
        this.videoWatchURL = videoWatchURL;
        this.videoDownloadURL = "";
        this.listeners = new ArrayList<PropertyChangeListener>();
    }

}
